package com.mikelouis.test.scala.proginscala.chapter12

import scala.collection.mutable.ArrayBuffer

/**
 * Created by yuazhu on 1/12/2015.
 */
class BasicIntQueue extends IntQueue {
  private val buf = new ArrayBuffer[Int]

  override def get: Int = buf.remove(0)

  override def put(x: Int): Unit = buf += x
}

abstract class IntQueue {
  def get: Int

  def put(x: Int)
}

object BasicIntQueue {
  def main(args: Array[String]) {
    val queue = new BasicIntQueue
    queue.put(10)
    queue.put(20)

    println(queue.get)
    println(queue.get)

    /** 把整数放入队列的时候对它加倍 */
    println("*****************************************")
    val doubleQueue = new DoubleBasicIntQueue
    doubleQueue.put(10)
    println(doubleQueue.get)

    // 等价: 在使用new实例化的时候混入特质
    val basicQueueWithDoubling = new BasicIntQueue with Doubling
    basicQueueWithDoubling.put(30)
    println(basicQueueWithDoubling.get)

    /** Incrementing */
    println("*****************************************")
    try {
      // 混入的次序非常重要, 粗略地说，越靠近右侧的特质越先起作用。当你调用带混入的类的方法时，最右侧特质的方法首先被调用
      // 如果那个方法调用了super，它调用其左侧特质的方法，以此类推。
      // 前面的例子里，Filtering的put首先被调用，因此它移除了开始的负整数。Incrementing的put第二个被调用，因此它对剩下的整数增量
      val incrementingQueue = new BasicIntQueue with Incrementing with Filtering
      incrementingQueue.put(-1)
      incrementingQueue.put(0)
      incrementingQueue.put(1)
      println(incrementingQueue.get)
      println(incrementingQueue.get)
      println(incrementingQueue.get)
    }
    catch {
      case ex: RuntimeException => println("RuntimeExceptiion caught: " + ex.getMessage)
    }

    /** 逆转特质的次序 */
    println("*****************************************")
    try {
      val incrementingQueue2 = new BasicIntQueue with Filtering with Incrementing
      incrementingQueue2.put(-1)
      incrementingQueue2.put(0)
      incrementingQueue2.put(1)
      println(incrementingQueue2.get)
      println(incrementingQueue2.get)
      println(incrementingQueue2.get)
    }
    catch {
      case ex: RuntimeException => println("RuntimeExceptiion caught: " + ex.getMessage)
    }
  }
}

/**
 * 把整数放入队列的时候对它加倍。
 * Doubling特质有两件好玩的事情。
 * 第一个是他定义了超类，IntQueue。这个定义意味着特质只能混入到扩展了IntQueue的类中
 * 第二件有趣的事情是特质在声明为抽象的方法中有一个super调用
 */
trait Doubling extends IntQueue {
  // super调用是动态绑定的
  abstract override def put(x: Int) = super.put(2 * x)
}

class DoubleBasicIntQueue extends BasicIntQueue with Doubling

trait Incrementing extends IntQueue {
  abstract override def put(x: Int): Unit = super.put(x + 1)
}

trait Filtering extends IntQueue {
  abstract override def put(x: Int): Unit = if (x >= 0) super.put(x)
}